package com.chenbei.erp.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chenbei.common.exception.LogicHandleException;
import com.chenbei.erp.domain.InventoryOrder;
import com.chenbei.erp.domain.InventoryOrderDetail;
import com.chenbei.erp.enums.InventoryOrderStatusEnum;
import com.chenbei.erp.enums.InventoryOrderTypeEnum;
import com.chenbei.erp.enums.InventoryTransactionTypeEnum;
import com.chenbei.erp.mapper.InventoryOrderMapper;
import com.chenbei.erp.service.IInventoryOrderService;
import com.chenbei.erp.vo.*;
import com.chenbei.erp.vo.req.SchedulingStorageReq;
import com.chenbei.erp.vo.req.InStorageReq;
import com.chenbei.erp.vo.req.OutStorageReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class InventoryOrderService extends ServiceImpl<InventoryOrderMapper, InventoryOrder> implements IInventoryOrderService {

    private final Object lock = new Object();

    @Autowired
    private InventoryService InventoryService;

    @Autowired
    private InventoryOrderDetailService InventoryOrderDetailService;

    @Override
    @Transactional
    public void inbound(InStorageReq InStorageReq) {
        if (InStorageReq.getStoreLocationProducts() == null || InStorageReq.getStoreLocationProducts().isEmpty()) {
            throw new LogicHandleException("入库的产品不能为空");
        } else {
            synchronized (lock) {
                InventoryOrder InventoryOrder = new InventoryOrder();
                InventoryOrder.setBatchNumber(buildBatchNumber());
                InventoryOrder.setStatus(InventoryOrderStatusEnum.CONFIRMED.getStatus());
                InventoryOrder.setRemark(InStorageReq.getRemark());
                InventoryOrder.setType(InventoryOrderTypeEnum.STORE_IN.getType());
                InventoryOrder.setInWarehouseId(InStorageReq.getWarehouseId());
                InventoryOrder.setUserId(InStorageReq.getUserId());
                InventoryOrder.setCreateTime(LocalDateTime.now());

                if (save(InventoryOrder)) {
                    BigDecimal totalPrice = BigDecimal.ONE;

                    List<InventoryOrderDetail> InventoryOrderDetails = new ArrayList<>();
                    for (InStorageLocationProductVo inStorageLocationProductVo : InStorageReq.getStoreLocationProducts()) {
                        InventoryOrderDetail InventoryOrderDetail = new InventoryOrderDetail();
                        InventoryOrderDetail.setOrderId(InventoryOrder.getId());
                        InventoryOrderDetail.setCreateTime(LocalDateTime.now());
                        InventoryOrderDetail.setUnitCost(inStorageLocationProductVo.getUnitCost());
                        InventoryOrderDetail.setProductId(inStorageLocationProductVo.getProductId());
                        InventoryOrderDetail.setProductNumber(inStorageLocationProductVo.getNumber());
                        InventoryOrderDetail.setInStorageLocationId(inStorageLocationProductVo.getInStorageLocationId());

                        InventoryOrderDetails.add(InventoryOrderDetail);
                        totalPrice = totalPrice.add(inStorageLocationProductVo.getUnitCost().multiply(BigDecimal.valueOf(inStorageLocationProductVo.getNumber())));

                        syncInventory(inStorageLocationProductVo.getProductId(), inStorageLocationProductVo.getNumber(), inStorageLocationProductVo.getInStorageLocationId(), InventoryTransactionTypeEnum.INBOUND, InStorageReq.getRemark());
                    }
                    InventoryOrderDetailService.saveBatch(InventoryOrderDetails);

                    InventoryOrder.setTotalPrice(totalPrice);
                    updateById(InventoryOrder);
                } else {
                    throw new LogicHandleException("入库失败");
                }
            }
        }
    }

    @Override
    @Transactional
    public void outbound(OutStorageReq OutStorageReq) {
        if (OutStorageReq.getStoreLocationProducts() == null || OutStorageReq.getStoreLocationProducts().isEmpty()) {
            throw new LogicHandleException("出库产品不能为空");
        } else {
            synchronized (lock) {
                boolean boolProductInventoryValid = true;               //校验产品库存
                for (OutStorageLocationProductVo outStorageLocationProductVo : OutStorageReq.getStoreLocationProducts()) {
                    if (InventoryService.getProductQuantity(outStorageLocationProductVo.getOutStorageLocationId(), outStorageLocationProductVo.getProductId()) < outStorageLocationProductVo.getNumber()) {
                        boolProductInventoryValid = false;
                        break;
                    }
                }
                if (!boolProductInventoryValid) {
                    throw new LogicHandleException("产品库存不足");
                }

                InventoryOrder InventoryOrder = new InventoryOrder();
                InventoryOrder.setBatchNumber(buildBatchNumber());
                InventoryOrder.setStatus(InventoryOrderStatusEnum.CONFIRMED.getStatus());
                InventoryOrder.setRemark(OutStorageReq.getRemark());
                InventoryOrder.setType(InventoryOrderTypeEnum.STORE_OUT.getType());
                InventoryOrder.setOutWarehouseId(OutStorageReq.getWarehouseId());
                InventoryOrder.setUserId(OutStorageReq.getUserId());
                InventoryOrder.setCreateTime(LocalDateTime.now());

                if(save(InventoryOrder)) {
                    BigDecimal totalPrice = BigDecimal.ONE;
                    List<InventoryOrderDetail> InventoryOrderDetails = new ArrayList<>();
                    for (OutStorageLocationProductVo outStorageLocationProductVo : OutStorageReq.getStoreLocationProducts()) {
                        InventoryOrderDetail InventoryOrderDetail = new InventoryOrderDetail();
                        InventoryOrderDetail.setOrderId(InventoryOrder.getId());
                        InventoryOrderDetail.setCreateTime(LocalDateTime.now());
                        InventoryOrderDetail.setUnitCost(outStorageLocationProductVo.getUnitCost());
                        InventoryOrderDetail.setProductId(outStorageLocationProductVo.getProductId());
                        InventoryOrderDetail.setProductNumber(outStorageLocationProductVo.getNumber());
                        InventoryOrderDetail.setOutStorageLocationId(outStorageLocationProductVo.getOutStorageLocationId());

                        InventoryOrderDetails.add(InventoryOrderDetail);
                        totalPrice = totalPrice.add(outStorageLocationProductVo.getUnitCost().multiply(BigDecimal.valueOf(outStorageLocationProductVo.getNumber())));

                        syncInventory(outStorageLocationProductVo.getProductId(), outStorageLocationProductVo.getNumber(), outStorageLocationProductVo.getOutStorageLocationId(), InventoryTransactionTypeEnum.OUTBOUND, OutStorageReq.getRemark());
                    }
                    InventoryOrderDetailService.saveBatch(InventoryOrderDetails);

                    InventoryOrder.setTotalPrice(totalPrice);
                    updateById(InventoryOrder);
                } else {
                    throw new LogicHandleException("出库失败");
                }
            }
        }
    }

    @Override
    @Transactional
    public void scheduling(SchedulingStorageReq SchedulingStorageReq) {
        if (SchedulingStorageReq.getStoreLocationProducts() == null || SchedulingStorageReq.getStoreLocationProducts().isEmpty()) {
            throw new LogicHandleException("调拨的产品不能为空");
        } else {
           synchronized (lock) {
               boolean boolProductInventoryValid = true;
               for (SchedulingStorageLocationProductVo schedulingStorageLocationProductVo : SchedulingStorageReq.getStoreLocationProducts()) {
                   if (InventoryService.getProductQuantity(schedulingStorageLocationProductVo.getOutStorageLocationId(), schedulingStorageLocationProductVo.getProductId()) < schedulingStorageLocationProductVo.getNumber()) {
                       boolProductInventoryValid = false;
                       break;
                   }
               }

               if (!boolProductInventoryValid) {
                   throw new LogicHandleException("产品库存不足");
               }

               InventoryOrder InventoryOrder = new InventoryOrder();
               InventoryOrder.setBatchNumber(buildBatchNumber());
               InventoryOrder.setStatus(InventoryOrderStatusEnum.CONFIRMED.getStatus());
               InventoryOrder.setRemark(SchedulingStorageReq.getRemark());
               InventoryOrder.setType(InventoryOrderTypeEnum.STORE_ALLOCATE.getType());
               InventoryOrder.setOutWarehouseId(SchedulingStorageReq.getOutWarehouseId());
               InventoryOrder.setInWarehouseId(SchedulingStorageReq.getInWarehouseId());
               InventoryOrder.setUserId(SchedulingStorageReq.getUserId());
               InventoryOrder.setCreateTime(LocalDateTime.now());
               InventoryOrder.setTotalPrice(BigDecimal.ONE);

               if (save(InventoryOrder)) {
                   List<InventoryOrderDetail> InventoryOrderDetails = new ArrayList<>();
                   for (SchedulingStorageLocationProductVo schedulingStorageLocationProductVo : SchedulingStorageReq.getStoreLocationProducts()) {
                       InventoryOrderDetail InventoryOrderDetail = new InventoryOrderDetail();
                       InventoryOrderDetail.setOrderId(InventoryOrder.getId());
                       InventoryOrderDetail.setCreateTime(LocalDateTime.now());
                       InventoryOrderDetail.setUnitCost(schedulingStorageLocationProductVo.getUnitCost());
                       InventoryOrderDetail.setProductId(schedulingStorageLocationProductVo.getProductId());
                       InventoryOrderDetail.setProductNumber(schedulingStorageLocationProductVo.getNumber());
                       InventoryOrderDetail.setInStorageLocationId(schedulingStorageLocationProductVo.getInStorageLocationId());
                       InventoryOrderDetail.setOutStorageLocationId(schedulingStorageLocationProductVo.getOutStorageLocationId());

                       InventoryOrderDetails.add(InventoryOrderDetail);
                       syncInventory(schedulingStorageLocationProductVo.getProductId(), schedulingStorageLocationProductVo.getNumber(), schedulingStorageLocationProductVo.getOutStorageLocationId(), InventoryTransactionTypeEnum.OUTBOUND, SchedulingStorageReq.getRemark());
                       syncInventory(schedulingStorageLocationProductVo.getProductId(), schedulingStorageLocationProductVo.getNumber(), schedulingStorageLocationProductVo.getInStorageLocationId(), InventoryTransactionTypeEnum.INBOUND, SchedulingStorageReq.getRemark());
                   }
                   InventoryOrderDetailService.saveBatch(InventoryOrderDetails);
               } else {
                   throw new LogicHandleException("调拨失败");
               }
           }
        }
    }

    /**
     * 生成批次号
     * @return String
     */
    private String buildBatchNumber() {
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String reservedArea = "0000";
        long count = count() + 1;
        return time + reservedArea + String.format("%08d", count);
    }

    /**
     * 同步库存
     * @param productId 产品ID
     * @param productNumber 产品数
     * @param storageLocationId 仓位ID
     * @param inventoryTransactionTypeEnum 交易类型
     * @param remark 备注
     */
    private void syncInventory(Long productId, Integer productNumber, Long storageLocationId, InventoryTransactionTypeEnum inventoryTransactionTypeEnum, String remark) {
        InventoryVo inventoryVo = new InventoryVo();
        inventoryVo.setRemark(remark);
        inventoryVo.setProductId(productId);
        inventoryVo.setProductNumber(productNumber);
        inventoryVo.setStorageLocationId(storageLocationId);
        inventoryVo.setTransactionType(inventoryTransactionTypeEnum.getType());
        InventoryService.saveOrUpdate(inventoryVo);
    }
}
